
重载解析通过比较调用的每个参数与候选函数对应参数的匹配程度，来对可行候选函数进行排序。为了使一个候选函数比另一个更好，更好的候选不能有参数比另一个候选的相应参数匹配的差。下面的例子说明了这一点:

\begin{lstlisting}[style=styleCXX]
void combine(int, double);
void combine(long, int);

int main()
{
	combine(1, 2); // ambiguous!
}
\end{lstlisting}

本例中，对combine()的调用具有歧义，因为第一个候选参数最匹配第一个参数(int类型的1字面值)，而第二个候选参数最匹配第二个参数。可以说int在某种意义上比double更接近long(支持选择第二个候选项)，但是C++并没有定义包含多个调用参数的匹配度指标。

有了这第一原则，就需要指定给定参数与可行候选参数的对应参数的匹配程度。作为第一次近似的候选，可以将可能的匹配按如下顺序排列(从最好到最差):

\begin{enumerate}
\item 
完美匹配。参数具有表达式的类型，或者具有指向表达式类型的引用类型(可能添加了const和/或volatile限定符)。

\item 
匹配需要微调。将数组变量衰变为指向其第一个元素的指针，或将const相加以匹配int**类型的参数和const* const* int类型的参数。


\item 
类型升级匹配。类型升级是一种隐式转换，包括将小整型(如bool、char、short，有时还包括枚举)转换为int、unsigned int、long或unsigned long，以及将float转换为double。


\item 
只匹配标准转换。任何类型的标准转换(如int到float)或从派生类到其公共、明确的基类的转换，但不包括对转换操作符或转换构造函数的隐式调用。


\item 
匹配用户定义的转换。这允许任何类型的隐式转换。


\item 
匹配省略号(…)，省略号参数几乎可以匹配任何类型，但有一个例外:具有重要复制构造函数的类型可能是有效的，也可能不是有效的(实现可以进行允许或禁止)。
\end{enumerate}

下面的例子展示了其中的一些匹配方式:

\begin{lstlisting}[style=styleCXX]
int f1(int); // #1
int f1(double); // #2
f1(4); // calls #1 : perfect match (#2 requires a standard conversion)

int f2(int); // #3
int f2(char); // #4
f2(true); // calls #3 : match with promotion
// (#4 requires stronger standard conversion)

class X {
	public:
	X(int);
};
int f3(X); // #5
int f3(...); // #6
f3(7); // calls #5 : match with user-defined conversion
// (#6 requires a match with ellipsis)
\end{lstlisting}

重载解析发生在模板参数推导后，而且推导不考虑所有这些类型的转换。例如:

\begin{lstlisting}[style=styleCXX]
template<typename T>
class MyString {
	public:
	MyString(T const*); // converting constructor
	...
};

template<typename T>
MyString<T> truncate(MyString<T> const&, int);

int main()
{
	MyString<char> str1, str2;
	str1 = truncate<char>("Hello World", 5); // OK
	str2 = truncate("Hello World", 5); // ERROR
}
\end{lstlisting}

模板参数推导期间，不会考虑通过转换构造函数提供的隐式转换。str2的赋值没有找到可行函数truncate()，因此不执行重载解析。

模板参数推导的上下文中，若对应的参数是左值，则对模板参数的右值引用可以推断为左值引用类型(在引用折叠之后)。若该参数是右值，则可以推断为右值引用类型(参见15.6节)。例如:

\begin{lstlisting}[style=styleCXX]
template<typename T> void strange(T&&, T&&);
template<typename T> void bizarre(T&&, double&&);

int main()
{
	strange(1.2, 3.4); // OK: with T deduced to double
	double val = 1.2;
	strange(val, val); // OK: with T deduced to double&
	strange(val, 3.4); // ERROR: conflicting deductions
	bizarre(val, val); // ERROR: lvalue val doesn’t match double&&
}
\end{lstlisting}

前面的原则只是一种近似方式，但覆盖了许多情况。有相当多的常见情况，这些规则没有充分解释。我们将继续讨论这些规则的最重要改进。

\subsubsubsection{C.2.1\hspace{0.2cm}成员函数的隐含参数}

对非静态成员函数的调用具有一个隐藏参数，成员函数的定义中可访问该参数为*this。对于类MyClass的成员函数，隐藏参数的类型通常为MyClass\&(用于非const成员函数)或MyClass const\&(用于const成员函数)。

\begin{tcolorbox}[colback=webgreen!5!white,colframe=webgreen!75!black]
\hspace*{0.75cm}若成员函数是volatile类型，也可以是MyClass volatile\&类型，或者MyClass const volatile\&类型，但这种情况非常罕见。
\end{tcolorbox}

考虑到其具有指针类型，如果让这个等于现在的*this就更好了。但这是C++早期版本的一部分，在引用类型成为语言的一部分之前，并且当添加引用类型时，太多的代码已经依赖于this指针了。

隐藏的*this参数和显式参数一样参与重载解析，但偶尔也会发生意外。下面的例子显示了一个类似字符串的类，其不能按预期工作(这种代码实际存在):

\begin{lstlisting}[style=styleCXX]
#include <cstddef>

class BadString {
	public:
	BadString(char const*);
	...
	
	// character access through subscripting:
	char& operator[] (std::size_t); // #1
	char const& operator[] (std::size_t) const;
	
	// implicit conversion to null-terminated byte string:
	operator char* (); // #2
	operator char const* ();
	...
};

int main()
{
	BadString str("correkt");
	str[5] = ’c’; // possibly an overload resolution ambiguity!
}
\end{lstlisting}

首先，表达式str[5]似乎没有任何问题。在\#1处的下标操作符似乎是完美的匹配。但并不完美，因为参数5是int类型，而操作符需要无符号整型(size\_t和std::size\_t通常有unsigned int类型或unsigned long类型，但从来没有int类型)。尽管如此，一个简单的标准整数转换使\#1很容易实现。还有另一种候选方法:内置下标操作符。若将隐式转换操作符应用于str(隐式成员函数参数)，就会获得指针类型，现在内置下标操作符也会应用。这个内置操作符接受一个ptrdiff\_t类型的参数，该参数在许多平台上等价于int，因此参数5完美匹配。因此，尽管内置下标操作符对隐含参数匹配的很差(通过用户定义的转换)，但比在\#1处定义的操作符对实际下标的匹配更好!因此，可能存在歧义。

\begin{tcolorbox}[colback=webgreen!5!white,colframe=webgreen!75!black]
\hspace*{0.75cm}这种歧义只存在于size\_t是unsigned int的平台上。在它是unsigned long平台上，类型ptrdiff\_t是long的类型别名，并且不存在歧义，因为内置的下标操作符也需要对下标表达式进行转换。
\end{tcolorbox}

为了可移植地解决这类问题，可以用一个ptrdiff\_t参数声明operator[]，或者可以用显式转换来替换隐式到char*的类型转换(这是推荐做法)。

一组候选成员可能同时包含静态成员和非静态成员。当比较静态成员和非静态成员时，将忽略隐式参数的匹配度(只有非静态成员具有隐式的*this参数)。

默认情况下，非静态成员函数有一个隐含的*this参数，是左值引用类型，但C++11引入了语法使其成为右值引用类型。例如:

\begin{lstlisting}[style=styleCXX]
struct S {
	void f1(); // implicit *this parameter is an lvalue reference (see below)
	void f2() &&; // implicit *this parameter is an rvalue reference
	void f3() &; // implicit *this parameter is an lvalue reference
};
\end{lstlisting}

从这个例子中可以看出，不仅可以使隐式参数成为右值引用(带\&\&后缀)，还可以确认左值引用情况(带\&后缀)。有趣的是，指定\&后缀并不完全等同于引用它:旧的特殊情况允许右值绑定到对非const类型的左值引用，当该引用是传统的隐式*this参数时，但若显式请求左值引用处理，这种特殊情况(有些危险)不再适用。因此，根据上面S的定义，有如下的结果:

\begin{lstlisting}[style=styleCXX]
int main()
{
	S().f1(); // OK: old rule allows rvalue S() to match implied
			// lvalue reference type S& of *this
	S().f2(); // OK: rvalue S() matches rvalue reference type
			// of *this
	S().f3(); // ERROR: rvalue S() cannot match explicit lvalue
			// reference type of *this
}
\end{lstlisting}


\subsubsubsection{C.2.2\hspace{0.2cm}改善完美匹配}

对于X类型的参数，有四种常见的参数类型可以构成完美匹配:X、X\&、X const\&和X\&\&(X const\&\&也是完美匹配，但很少使用)。但是，在两种引用上重载函数是很常见的。C++11之前，这意味着:

\begin{lstlisting}[style=styleCXX]
void report(int&); // #1
void report(int const&); // #2

int main()
{
	for (int k = 0; k<10; ++k) {
		report(k); // calls #1
	}
	report(42); // calls #2
}
\end{lstlisting}

没有其他的const的版本更适合用于左值，而只有带有const的版本才能匹配右值。

随着C++11中右值引用的引入，需要区分两个完全匹配的另一种常见情况如下所示:

\begin{lstlisting}[style=styleCXX]
struct Value {
	...
};
void pass(Value const&); // #1
void pass(Value&&); // #2

void g(X&& x)
{
	pass(x); // calls #1 , because x is an lvalue
	pass(X()); // calls #2 , because X() is an rvalue (in fact, prvalue)
	pass(std::move(x)); // calls #2 , because std::move(x) is an rvalue (in fact, xvalue)
}
\end{lstlisting}

这次，采用右值引用的版本认为是右值的更好匹配，但不能匹配左值。

这也适用于成员函数调用的隐式参数:

\begin{lstlisting}[style=styleCXX]
class Wonder {
	public:
	void tick(); // #1
	void tick() const; // #2
	void tack() const; // #3
};

void run(Wonder& device)
{
	device.tick(); // calls #1
	device.tack(); // calls #3 , because there is no non-const version
				  // of Wonder::tack()
}
\end{lstlisting}

最后，下面代码对前面示例的修改说明，不管使用和不使用引用，两个完美匹配都会产生歧义:

\begin{lstlisting}[style=styleCXX]
void report(int); // #1
void report(int&); // #2
void report(int const&); // #3

int main()
{
	for (int k = 0; k<10; ++k) {
		report(k); // ambiguous: #1 and #2 match equally well
	}
report(42); // ambiguous: #1 and #3 match equally well
}
\end{lstlisting}








